package library.utils;

import android.app.Activity;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.text.TextUtils;
import android.webkit.MimeTypeMap;

import java.io.File;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;

import library.bean.ApkInfo;
import library.logger.Logger;


public class ApkUtils {

    public static boolean isInstalled(Context context, String packageName) {
        PackageManager pm = context.getPackageManager();
        try {
            pm.getPackageInfo(packageName, PackageManager.GET_ACTIVITIES);
            return true;
        } catch (NameNotFoundException e) {
        }

        return false;
    }

    public static String getInstalledApkPath(Context context, String packageName) {
        try {
            ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo(packageName, 0);
            return appInfo.sourceDir;
        } catch (NameNotFoundException e) {
            Logger.debug(e);
        }

        return null;
    }


    public static boolean installApk(Context context, File file) {
        if (file == null || !file.exists() || !file.isFile())
            return false;
        return installApk(context, Uri.fromFile(file));
    }

    public static boolean installApk(Context context, Uri uri) {
        if (context == null || uri == null)
            return false;
        try {
            Intent intent = new Intent(Intent.ACTION_VIEW);
            String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension("apk");
            intent.setDataAndType(uri, mimeType/*"application/vnd.android.package-archive"*/);
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(intent);
            return true;
        } catch (Exception e) {
            Logger.debug(e);
        }
        return false;
    }

    private static PackageManager getPackageManager(Context context) {
        return context.getPackageManager();
    }

    public static PackageInfo getPackageInfo(Context context) throws NameNotFoundException {
        return getPackageManager(context).getPackageInfo(context.getPackageName(), 0);
    }

    public static ApplicationInfo getApplicationInfo(Context context) {
        try {
            return getPackageManager(context).getApplicationInfo(context.getPackageName(), 0);
        } catch (Exception e) {
            Logger.debug(e);
        }
        return null;
    }

    public static String getPackageName(Context context) {
        if (context == null)
            return null;
        try {
            return getPackageInfo(context).packageName;
        } catch (Exception e) {
            Logger.debug(e);
        }
        return context.getPackageName();
    }

    public static int getVersionCode(Context context) {
        try {
            return getPackageInfo(context).versionCode;
        } catch (Exception e) {
            Logger.debug(e);
        }
        return 0;
    }

    public static String getVersionName(Context context) {
        try {
            return getPackageInfo(context).versionName;
        } catch (Exception e) {
            Logger.debug(e);
        }
        return null;
    }

    public static Drawable getIcon(Context context) {
        try {
            PackageManager pm = context.getPackageManager();
            ApplicationInfo info = pm.getApplicationInfo(context.getPackageName(), 0);
            return info.loadIcon(pm);
        } catch (Exception e) {
            Logger.debug(e);
        }
        return null;
    }

    public static String getLauncherPackageName(Context context) {
        final Intent intent = new Intent(Intent.ACTION_MAIN);
        intent.addCategory(Intent.CATEGORY_HOME);
        final ResolveInfo res = context.getPackageManager().resolveActivity(intent, 0);
        if (res.activityInfo == null) {
            return null;
        }
        if (res.activityInfo.packageName.equals("android")) {
            return null;
        } else {
            return res.activityInfo.packageName;
        }
    }

    public static boolean isLauncher(Context context) {
        final String launcher = getLauncherPackageName(context);
        final String packageName = ApkUtils.getPackageName(context);
        if (launcher != null && packageName != null && launcher.equals(packageName)) {
            return true;
        }
        return false;
    }

    public static Bundle getMetaDataFromApplication(Context context) {
        try {
            ApplicationInfo info = context.getPackageManager().getApplicationInfo(getPackageName(context), PackageManager.GET_META_DATA);
            return info.metaData;
        } catch (NameNotFoundException e) {
            Logger.debug(e);
        }
        return null;
    }

    public static Bundle getMetaDataFromService(Context context, Class<? extends Service> service) {
        try {
            ComponentName cn = new ComponentName(context, service);
            ServiceInfo info = context.getPackageManager().getServiceInfo(cn, PackageManager.GET_META_DATA);
            return info.metaData;
        } catch (NameNotFoundException e) {
            Logger.debug(e);
        }
        return null;
    }

    public static Bundle getMetaDataFromActivity(Context context, Class<? extends Activity> activity) {
        try {
            ComponentName cn = new ComponentName(context, activity);
            ActivityInfo info = context.getPackageManager().getActivityInfo(cn, PackageManager.GET_META_DATA);
            return info.metaData;
        } catch (NameNotFoundException e) {
            Logger.debug(e);
        }
        return null;
    }

    public static Bundle getMetaDataFromReceiver(Context context, Class<? extends BroadcastReceiver> receiver) {
        try {
            ComponentName cn = new ComponentName(context, receiver);
            ActivityInfo info = context.getPackageManager().getActivityInfo(cn, PackageManager.GET_META_DATA);
            return info.metaData;
        } catch (NameNotFoundException e) {
            Logger.debug(e);
        }
        return null;
    }

    public static String getKeyStoreSHA1(Context context) {
        try {
            PackageInfo info = context.getPackageManager().getPackageInfo(
                    context.getPackageName(), PackageManager.GET_SIGNATURES);
            byte[] cert = info.signatures[0].toByteArray();
            MessageDigest md = MessageDigest.getInstance("SHA1");
            byte[] publicKey = md.digest(cert);
            StringBuffer hexString = new StringBuffer();
            for (int i = 0; i < publicKey.length; i++) {
                String appendString = Integer.toHexString(0xFF & publicKey[i]).toUpperCase(Locale.US);
                if (appendString.length() == 1)
                    hexString.append("0");
                hexString.append(appendString);
                hexString.append(":");
            }
            String result = hexString.toString();
            return result.substring(0, result.length() - 1);
        } catch (NameNotFoundException e) {
            Logger.debug(e);
        } catch (NoSuchAlgorithmException e) {
            Logger.debug(e);
        }
        return null;
    }

    public static String getSignature(Context context) {
        return getSignatureFromInstalledPackage(context, context.getPackageName());
    }

    public static String getSignatureFromInstalledPackage(Context context, String packageName) {
        if (!TextUtils.isEmpty(packageName)) {
            PackageManager pm = context.getPackageManager();
            List<PackageInfo> apps = pm.getInstalledPackages(PackageManager.GET_SIGNATURES);

            Iterator<PackageInfo> iter = apps.iterator();
            while (iter.hasNext()) {
                PackageInfo packageinfo = iter.next();
                String thisName = packageinfo.packageName;
                if (thisName.equals(packageName)) {
                    return packageinfo.signatures[0].toCharsString();
                }
            }
        }
        return null;
    }


    /**
     * @param apkFile 文件的全路径信息（包括apk文件的名称），如果是无效的apk文件，返回值为null
     * @return
     */
    public static String getSignatureFromFile(Context context, String apkFile) {
        PackageManager pm = getPackageManager(context);
        PackageInfo newInfo = pm.getPackageArchiveInfo(apkFile, PackageManager.GET_ACTIVITIES | PackageManager.GET_SIGNATURES);
        if (newInfo != null) {
            if (newInfo.signatures != null && newInfo.signatures.length > 0) {
                return newInfo.signatures[0].toCharsString();
            }
        }
        return null;
    }

    public static ApkInfo getArchiveInfo(Context context, File file) {
        if (context == null)
            return null;
        if (file == null || !file.exists() || !file.isFile()) {
            Logger.debug(new Exception("File not found : " + file));
            return null;
        }
        try {
            ApkInfo bean = new ApkInfo(file);
            PackageManager pm = getPackageManager(context);
            PackageInfo info;
            info = pm.getPackageArchiveInfo(file.getAbsolutePath(), PackageManager.GET_ACTIVITIES);
            if (info != null) {
                ApplicationInfo appInfo = info.applicationInfo;
                bean.setPackageName(appInfo.packageName);
                bean.setVersionName(info.versionName);
                bean.setVersionCode(info.versionCode);
                bean.setIcon(pm.getApplicationIcon(appInfo));
            } else {
                throw new Exception("The archive is invalid.");
            }

            bean.setSign(getSignatureFromFile(context, file.getAbsolutePath()));

            info = pm.getPackageArchiveInfo(file.getAbsolutePath(), PackageManager.GET_ACTIVITIES | PackageManager.GET_SIGNATURES);
            if (info != null) {
                byte[] cert = info.signatures[0].toByteArray();
                MessageDigest md = MessageDigest.getInstance("SHA1");
                byte[] publicKey = md.digest(cert);
                StringBuffer hexString = new StringBuffer();
                for (int i = 0; i < publicKey.length; i++) {
                    String appendString = Integer.toHexString(0xFF & publicKey[i])
                            .toUpperCase(Locale.US);
                    if (appendString.length() == 1)
                        hexString.append("0");
                    hexString.append(appendString);
                    hexString.append(":");
                }
                String result = hexString.toString();
                bean.setSignSHA1(result.substring(0, result.length() - 1));
            }
            return bean;
        } catch (Exception e) {
            Logger.debug(e);
        }
        return null;
    }

    public static Object getAppName(Context context) {
        PackageManager pm = getPackageManager(context);
        try {
            PackageInfo pkg = pm.getPackageInfo(getPackageName(context), 0);
            String appName = pkg.applicationInfo.loadLabel(pm).toString();
            return appName;
        } catch (NameNotFoundException e) {

        }
        return null;
    }
}
